using System;
using System.Data;
using System.Xml;
using System.Data.Common;
using System.Collections;
using MCMLXVII.Core.Common;

namespace MCMLXVII.BackEnd.Data
{
    internal class TransactionConnections
    {
        private Hashtable _Connections;
        private DateTime _Started;
        private string _ID;

        public TransactionConnections(string ID)
        {
            _ID = ID;
            _Started = DateTime.Now;
            _Connections = new Hashtable();
        }

        public DbConnection GetConnection(string ConnectionString)
        {
            if (_Connections.ContainsKey(ConnectionString))
            {
                return (DbConnection)_Connections[ConnectionString];
            }
            else
            {
                return null;
            }
        
        }

        public bool HasConnection(string ConnectionString)
        {
            return (_Connections.ContainsKey(ConnectionString));
        }


        public void AddConnection(string ConnectionString, DbConnection Connection)
        {
            _Connections.Add(ConnectionString, Connection );
        }

        public void CloseAll()
        {
            foreach (object con in _Connections.Values)
            {
                try
                {
                    ((DbConnection)con).Close();
                }
                catch
                { }
            }
        }
    }



    public static class TransactionsOptimizer
    {
        private static Hashtable _Transactions = new Hashtable();
        private static DbProviderFactory Factory;
        
        static TransactionsOptimizer ()
	    {
            Factory = DbProviderFactories.GetFactory(Configuration.Instance.GetSystemParameter("SystemConnectionProviderString"));
	    }

        public static void StartTransaction(string TransactionID)
        {
            lock (_Transactions.SyncRoot)
            {
                _Transactions.Add(TransactionID, new TransactionConnections(TransactionID));            
            }
        }


        public static void StopTransaction(string TransactionID)
        {
            TransactionConnections tc = null;
            lock (_Transactions.SyncRoot)
            {
                if (_Transactions.ContainsKey(TransactionID))
                {
                    tc = (TransactionConnections)_Transactions[TransactionID];
                    _Transactions.Remove(TransactionID);
                }                
            }
            if (tc != null)
                tc.CloseAll();
        }


        public static DbConnection GetFreeConnection()
        {
            return GetFreeConnection(Configuration.Instance.GetSystemParameter("SystemConnectionString"));
        }

        public static DbConnection GetFreeConnection(string ConnectrionString)
        {
            DbConnection con = Factory.CreateConnection();
            con.ConnectionString = ConnectrionString;
            con.Open();
            return con;
        }

        public static DbConnection GetConnection(out bool MustBeClosed)
        {
            return GetConnection( Configuration.Instance.GetSystemParameter("SystemConnectionString"), out MustBeClosed);
        }
        

        public static DbConnection GetConnection(string ConnectrionString, out bool MustBeClosed)
        {
            if (System.Transactions.Transaction.Current != null)
            {
                string id = System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier;
                TransactionConnections tsc = null;
                lock (_Transactions.SyncRoot)
                {
                    if (!_Transactions.ContainsKey(id))
                    {
                        throw new Exception("Transaction not enabled");
                    }
                    else
                    {
                        tsc = (TransactionConnections)_Transactions[id];
                    }
                }
                if (tsc.HasConnection(ConnectrionString))
                {
                    MustBeClosed = false;
                    return tsc.GetConnection(ConnectrionString);
                }
                else
                {
                    MustBeClosed = false;
                    DbConnection con = Factory.CreateConnection();
                    con.ConnectionString = ConnectrionString;
                    con.Open();
                    tsc.AddConnection(ConnectrionString, con);
                    return con;
                }
            }
            else
            {
                
                DbConnection con = Factory.CreateConnection();
                con.ConnectionString = ConnectrionString;
                con.Open();
                MustBeClosed = true;
                return con;
            }
        }

        public static DbCommand GetCommand()
        {
            return Factory.CreateCommand();
        }
    }
}
